using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
using Microsoft.Xna.Framework.Input;
using System;
using System.IO;
using System.Windows.Forms;
using Nuclex.Input;
using Nuclex.UserInterface;
using Microsoft.Xna.Framework.Media;

namespace FierceWar
{
	public class Game1 : Game
	{
		#region Fields.
		GraphicsDeviceManager graphics;
		SpriteBatch spriteBatch;

		// Input manager.
		InputManager input;
		// Gui manager.
		GuiManager gui;

		// Window form.
		Form form;

		// Resources.
		GameResources resources;

		Rectangle crosshairsRectangle;

		// Screens.
		MainMenuScreen mainMenuScreen;
		PlayingScreen playingScreen;
		AboutScreen aboutScreen;
		CreateMapOptionScreen createMapOptionScreen;
		CreateMapScreen createMapScreen;
		BuildMapPopupMenuScreen createMapPopupMenuScreen;
		BuildMapHelpScreen createMapHelpScreen;
		EditMapScreen editMapScreen;
		BuildMapPopupMenuScreen editMapPopupMenuScreen;
		BuildMapHelpScreen editMapHelpScreen;
		LoadingScreen loadingScreen;
		PauseScreen pauseScreen;
		FadeScreen fadeScreen;
		Screen currentScreen;

		// Dialogs.
		ConfirmQuitDialog confirmQuitDialog;
		LoadMapDialog loadMapDialog;
		SaveMapDialog saveMapDialog;
		NotifySaveMapDialog notifySaveMapDialog;
		#endregion

		#region Initilization.
		public Game1()
		{
			graphics = new GraphicsDeviceManager(this);
			Content.RootDirectory = "Content";

			input = new InputManager(Services, Window.Handle);
			Components.Add(input);

			gui = new GuiManager(Services);
			gui.DrawOrder = 1000;
			Components.Add(gui);

			graphics.PreferredBackBufferWidth = 1280;
			graphics.PreferredBackBufferHeight = 600;

			Window.Title = "Fierce War - Survive if You Can";

			form = (Form)Form.FromHandle(Window.Handle);
			if (form != null)
			{
				form.FormClosing += new FormClosingEventHandler(form_FormClosing);
			}

			IsMouseVisible = true;
		}

		// Called when the game should load its content
		protected override void LoadContent()
		{
			spriteBatch = new SpriteBatch(GraphicsDevice);

			Viewport viewport = GraphicsDevice.Viewport;
			Nuclex.UserInterface.Screen mainScreen =
				new Nuclex.UserInterface.Screen(viewport.Width, viewport.Height);
			this.gui.Screen = mainScreen;

			resources = new GameResources(GraphicsDevice, Window, spriteBatch,
				Content);

			crosshairsRectangle = new Rectangle(
				(GraphicsDevice.Viewport.Width - resources.Crosshairs.Width) / 2,
				(GraphicsDevice.Viewport.Height - resources.Crosshairs.Height) / 2,
				resources.Crosshairs.Width, resources.Crosshairs.Height);

			MouseInput.GraphicsDevice = GraphicsDevice;
			MouseInput.Window = Window;

			#region Screens.
			#region MainMenuScreen.
			List<EventHandler> eventHandlers = new List<EventHandler>() {
						 MainMenuScreenPlayGameEvent,
						 MainMenuScreenCreateMapEvent,
						 MainMenuScreenOptionEvent,
						 MainMenuScreenHelpEvent,
						 MainMenuScreenAboutEvent,
						 MainMenuScreenExitEvent,
			};
			mainMenuScreen = new MainMenuScreen(resources, eventHandlers);
			#endregion

			#region PlayingScreen.
			eventHandlers = new List<EventHandler>() {
						 PlayingScreenPauseEvent,
						 PlayingScreenQuitEvent,
			};
			playingScreen = new PlayingScreen(resources, eventHandlers);
			#endregion

			#region AboutScreen.
			aboutScreen = new AboutScreen(resources,
					new EventHandler(AboutScreenBackEvent));
			#endregion

			#region CreateMapOptionScreen.
			eventHandlers = new List<EventHandler>() {
						 CreateMapOptionScreenCreateEvent,
						 CreateMapOptionScreenEditEvent,
						 CreateMapOptionScreenBackEvent,
			};
			createMapOptionScreen =
				new CreateMapOptionScreen(resources, eventHandlers);
			#endregion

			#region CreateMapScreen.
			eventHandlers = new List<EventHandler>() {
						 CreateMapScreenPauseEvent,
						 CreateMapScreenQuitEvent,
						 CreateMapScreenSaveEvent,
						 CreateMapScreenSaveAsEvent,
						 CreateMapScreenHelpEvent,
			};
			createMapScreen = new CreateMapScreen(resources, eventHandlers);
			#endregion

			#region BuildMapPopupMenuScreen - CreateMapPopupMenuScreen.
			eventHandlers = new List<EventHandler>() {
						 CreateMapPopupMenuScreenSaveEvent,
						 CreateMapPopupMenuScreenSaveAsEvent,
						 CreateMapPopupMenuScreenHelpEvent,
						 CreateMapPopupMenuScreenResumeEvent,
						 CreateMapPopupMenuScreenQuitEvent,
						 CreateMapPopupMenuScreenResumeEvent,
			};
			createMapPopupMenuScreen = new BuildMapPopupMenuScreen(
				resources, eventHandlers, createMapScreen);
			#endregion

			#region BuildMapHelpScreen - CreateMapHelpScreen.
			createMapHelpScreen = new BuildMapHelpScreen(resources,
				new EventHandler(CreateMapHelpScreenCloseEvent), createMapScreen);
			#endregion

			#region EditMapScreen.
			eventHandlers = new List<EventHandler>() {
						 EditMapScreenPauseEvent,
						 EditMapScreenQuitEvent,
						 EditMapScreenSaveEvent,
						 EditMapScreenSaveAsEvent,
						 EditMapScreenHelpEvent,
			};
			editMapScreen = new EditMapScreen(resources, eventHandlers);
			#endregion

			#region BuildMapPopupMenuScreen - EditMapPopupMenuScreen.
			eventHandlers = new List<EventHandler>() {
						 EditMapPopupMenuScreenSaveEvent,
						 EditMapPopupMenuScreenSaveAsEvent,
						 EditMapPopupMenuScreenHelpEvent,
						 EditMapPopupMenuScreenResumeEvent,
						 EditMapPopupMenuScreenQuitEvent,
						 EditMapPopupMenuScreenResumeEvent,
			};
			editMapPopupMenuScreen = new BuildMapPopupMenuScreen(
				resources, eventHandlers, editMapScreen);
			#endregion

			#region BuildMapHelpScreen - EditMapHelpScreen.
			editMapHelpScreen = new BuildMapHelpScreen(resources,
				new EventHandler(EditMapHelpScreenCloseEvent), editMapScreen);
			#endregion

			#region LoadingScreen.
			loadingScreen = new LoadingScreen(
					resources, new EventHandler(LoadingScreenEvent),
					"", 3000.0f, 50.0f);
			#endregion

			#region PauseScreen.
			pauseScreen =
					new PauseScreen(resources, new EventHandler(PauseScreenEvent));
			#endregion

			#region FadeScreen.
			fadeScreen = new FadeScreen(resources, null);
			#endregion 
			#endregion

			// Set current screen.
			currentScreen = mainMenuScreen;
			mainMenuScreen.PlayMusic();

			#region Dialogs.
			#region ConfirmQuitDialog.
			eventHandlers = new List<EventHandler>() {
						 ConfirmQuitDialogYesEvent,
					     ConfirmQuitDialogNoEvent,
			};
			confirmQuitDialog = new ConfirmQuitDialog(GraphicsDevice, eventHandlers);
			#endregion

			#region LoadMapDialog.
			eventHandlers = new List<EventHandler>() {
					     LoadMapDialogLoadEvent,
					     LoadMapDialogCancelEvent,
			};
			loadMapDialog = new LoadMapDialog(GraphicsDevice, eventHandlers);
			#endregion

			#region SaveMapDialog.
			eventHandlers = new List<EventHandler> {
						 SaveMapDialogSaveEvent,
						 SaveMapDialogCancelEvent,
			};
			saveMapDialog = new SaveMapDialog(GraphicsDevice, eventHandlers);
			#endregion 

			#region NotifySaveMapDialog.
			eventHandlers = new List<EventHandler>() {
						 NotifySaveMapDialogYesEvent,
						 NotifySaveMapDialogNoEvent,
						 NotifySaveMapDialogCancelEvent,
			};
			notifySaveMapDialog =
				new NotifySaveMapDialog(GraphicsDevice, eventHandlers);
			#endregion
			#endregion
		}

		protected override void UnloadContent()
		{
			base.UnloadContent();
			Content.Unload();
		}
		#endregion

		#region Update and Draw.
		// Called when the game should update itself
		protected override void Update(GameTime gameTime)
		{
			// Get new state of keyboard and mouse.
			KeyboardInput.Update();
			MouseInput.Update();

			currentScreen.Update(gameTime);

			base.Update(gameTime);
		}

		// Called when the game should draw itself
		protected override void Draw(GameTime gameTime)
		{
            GraphicsDevice.Clear(Color.CornflowerBlue);

			resources.SpriteBatch.Begin();
			currentScreen.Draw(gameTime);
			if ((currentScreen == playingScreen) &&
				(!playingScreen.IsMouseVisible))
			{
				IsMouseVisible = false;
				resources.SpriteBatch.Draw(resources.Crosshairs,
					crosshairsRectangle, Color.Tomato);
			}
			else
			{
				IsMouseVisible = true;
			}
			resources.SpriteBatch.End();

			base.Draw(gameTime);
		}
		#endregion

		#region Event handle.
		#region Form.
		private void form_FormClosing(object sender, FormClosingEventArgs e)
		{
			if ((currentScreen == mainMenuScreen) ||
				(currentScreen == createMapScreen) ||
				(currentScreen == editMapScreen) ||
                (currentScreen == playingScreen))
			{
				fadeScreen.BackgroundScreen = currentScreen;
				if ((currentScreen is BuildMapScreen) &&
					(!((BuildMapScreen)currentScreen).IsSaved))
				{
					gui.Screen.Desktop.Children.Add(notifySaveMapDialog);
				}
				else
				{
					gui.Screen.Desktop.Children.Add(confirmQuitDialog);
				}

				currentScreen = fadeScreen;
				e.Cancel = true;
			}
			else if (currentScreen == fadeScreen)
			{
				if (confirmQuitDialog.IsExitGame)
				{
					e.Cancel = false;
				}
				else
				{
					e.Cancel = true;
				}
			}
			else
			{
				e.Cancel = true;
			}
		}
		#endregion

		#region MainMenuScreen.
		private void MainMenuScreenPlayGameEvent(object sender, EventArgs e)
		{
			loadingScreen.Duration = 10000.0f;
			loadingScreen.Message.TimeToNextLetter = 50.0f;
			loadingScreen.Message.Message = "LOADING...";
			loadingScreen.ResetLoadingBarColor();
			loadingScreen.BackgroundImage =
				LoadingScreen.BackgroundImageMode.LoadPlayingScreen;
            loadingScreen.NextScreen = playingScreen;

			currentScreen.StopMusic();
			currentScreen = loadingScreen;
		}

		private void MainMenuScreenCreateMapEvent(object sender, EventArgs e)
		{
			currentScreen = createMapOptionScreen;
		}

		private void MainMenuScreenOptionEvent(object sender, EventArgs e)
		{

		}

		private void MainMenuScreenHelpEvent(object sender, EventArgs e)
		{

		}

		private void MainMenuScreenAboutEvent(object sender, EventArgs e)
		{
			currentScreen = aboutScreen;
		}

		private void MainMenuScreenExitEvent(object sender, EventArgs e)
		{
			form.Close();
		}
		#endregion

		#region PlayingScreen.
        private void PlayingScreenPauseEvent(object sender, EventArgs e)
        {
            pauseScreen.BackgroundScreen = playingScreen;
            currentScreen = pauseScreen;
        }

        private void PlayingScreenQuitEvent(object sender, EventArgs e)
        {
            fadeScreen.BackgroundScreen = playingScreen;
            currentScreen = fadeScreen;

            gui.Screen.Desktop.Children.Add(confirmQuitDialog);
        }
		#endregion

		#region AboutScreen.
		private void AboutScreenBackEvent(object sender, EventArgs e)
		{
			aboutScreen.Reset();
			currentScreen = mainMenuScreen;
		}
		#endregion

		#region CreateMapOptionScreen.
		private void CreateMapOptionScreenCreateEvent(object sender, EventArgs e)
		{
			loadingScreen.Message.Message = "CREATING EMPTY MAP...";
			loadingScreen.Duration = 3000.0f;
			loadingScreen.Message.TimeToNextLetter = 50.0f;
			loadingScreen.LoadingBar.BorderColor = Color.Black * 0.5f;
			loadingScreen.BackgroundImage =
				LoadingScreen.BackgroundImageMode.LoadCreateMapScreen;
			loadingScreen.NextScreen = createMapScreen;

			currentScreen.StopMusic();
			currentScreen = loadingScreen;
		}

		private void CreateMapOptionScreenEditEvent(object sender, EventArgs e)
		{
			fadeScreen.BackgroundScreen = createMapOptionScreen;
			currentScreen = fadeScreen;

			loadMapDialog.UpdateList();
			gui.Screen.Desktop.Children.Add(loadMapDialog);
		}

		private void CreateMapOptionScreenBackEvent(object sender, EventArgs e)
		{
			currentScreen = mainMenuScreen;
		}
		#endregion

		#region CreateMapScreen.
		private void CreateMapScreenPauseEvent(object sender, EventArgs e)
		{
			pauseScreen.BackgroundScreen = createMapScreen;
			currentScreen = pauseScreen;
		}

		private void CreateMapScreenQuitEvent(object sender, EventArgs e)
		{
			currentScreen = createMapPopupMenuScreen;
		}

		private void CreateMapScreenSaveEvent(object sender, EventArgs e)
		{
			fadeScreen.BackgroundScreen = createMapScreen;
			currentScreen = fadeScreen;

			saveMapDialog.Title = "Save Map";
			gui.Screen.Desktop.Children.Add(saveMapDialog);
		}

		private void CreateMapScreenSaveAsEvent(object sender, EventArgs e)
		{
			fadeScreen.BackgroundScreen = createMapScreen;
			currentScreen = fadeScreen;

			saveMapDialog.Title = "Save Map As";
			gui.Screen.Desktop.Children.Add(saveMapDialog);
		}

		private void CreateMapScreenHelpEvent(object sender, EventArgs e)
		{
			currentScreen = createMapHelpScreen;
		}
		#endregion

		#region BuildMapPopupMenuScreen - CreateMapPopupMenuScreen.
		private void CreateMapPopupMenuScreenSaveEvent(object sender, EventArgs e)
		{
			fadeScreen.BackgroundScreen = createMapScreen;
			currentScreen = fadeScreen;

			saveMapDialog.Title = "Save Map";
			gui.Screen.Desktop.Children.Add(saveMapDialog);
		}

		private void CreateMapPopupMenuScreenSaveAsEvent(object sender, EventArgs e)
		{
			fadeScreen.BackgroundScreen = createMapScreen;
			currentScreen = fadeScreen;

			saveMapDialog.Title = "Save Map As";
			gui.Screen.Desktop.Children.Add(saveMapDialog);
		}

		private void CreateMapPopupMenuScreenHelpEvent(object sender, EventArgs e)
		{
			currentScreen = createMapHelpScreen;
		}

		private void CreateMapPopupMenuScreenResumeEvent(object sender, EventArgs e)
		{
			currentScreen = createMapScreen;
		}

		private void CreateMapPopupMenuScreenQuitEvent(object sender, EventArgs e)
		{
			fadeScreen.BackgroundScreen = createMapScreen;
			if (createMapScreen.IsSaved)
			{
				gui.Screen.Desktop.Children.Add(confirmQuitDialog);
			}
			else
			{
				gui.Screen.Desktop.Children.Add(notifySaveMapDialog);
			}
			currentScreen = fadeScreen;
		}
		#endregion

		#region BuildMapHelpScreen - CreateMapHelpScreen.
		private void CreateMapHelpScreenCloseEvent(object sender, EventArgs e)
		{
			createMapHelpScreen.Reset();
			currentScreen = createMapScreen;
		}
		#endregion

		#region EditMapScreen.
		private void EditMapScreenPauseEvent(object sender, EventArgs e)
		{
			pauseScreen.BackgroundScreen = editMapScreen;
			currentScreen = pauseScreen;
		}

		private void EditMapScreenQuitEvent(object sender, EventArgs e)
		{
			currentScreen = editMapPopupMenuScreen;
		}

		private void EditMapScreenSaveEvent(object sender, EventArgs e)
		{
			fadeScreen.BackgroundScreen = editMapScreen;
			currentScreen = fadeScreen;

			saveMapDialog.Title = "Save Map";
			gui.Screen.Desktop.Children.Add(saveMapDialog);
		}

		private void EditMapScreenSaveAsEvent(object sender, EventArgs e)
		{
			fadeScreen.BackgroundScreen = editMapScreen;
			currentScreen = fadeScreen;

			saveMapDialog.Title = "Save Map As";
			gui.Screen.Desktop.Children.Add(saveMapDialog);
		}

		private void EditMapScreenHelpEvent(object sender, EventArgs e)
		{
			currentScreen = editMapHelpScreen;
		}
		#endregion

		#region BuildMapPopupMenuScreen - EditMapPopupMenuScreen.
		private void EditMapPopupMenuScreenSaveEvent(object sender, EventArgs e)
		{
			fadeScreen.BackgroundScreen = editMapScreen;
			currentScreen = fadeScreen;

			saveMapDialog.Title = "Save Map";
			gui.Screen.Desktop.Children.Add(saveMapDialog);
		}

		private void EditMapPopupMenuScreenSaveAsEvent(object sender, EventArgs e)
		{
			fadeScreen.BackgroundScreen = editMapScreen;
			currentScreen = fadeScreen;

			saveMapDialog.Title = "Save Map As";
			gui.Screen.Desktop.Children.Add(saveMapDialog);
		}

		private void EditMapPopupMenuScreenHelpEvent(object sender, EventArgs e)
		{
			currentScreen = editMapHelpScreen;
		}

		private void EditMapPopupMenuScreenResumeEvent(object sender, EventArgs e)
		{
			currentScreen = editMapScreen;
		}

		private void EditMapPopupMenuScreenQuitEvent(object sender, EventArgs e)
		{
			fadeScreen.BackgroundScreen = editMapScreen;
			if (editMapScreen.IsSaved)
			{
				gui.Screen.Desktop.Children.Add(confirmQuitDialog);
			}
			else
			{
				gui.Screen.Desktop.Children.Add(notifySaveMapDialog);
			}
			currentScreen = fadeScreen;
		}
		#endregion

		#region BuildMapHelpScreen - EditMapHelpScreen.
		private void EditMapHelpScreenCloseEvent(object sender, EventArgs e)
		{
			editMapHelpScreen.Reset();
			currentScreen = editMapScreen;
		}
		#endregion

		#region LoadingScreen.
		private void LoadingScreenEvent(object sender, EventArgs e)
		{
			currentScreen = loadingScreen.NextScreen;
			loadingScreen.NextScreen.PlayMusic();
		}
		#endregion

		#region PauseScreen.
		private void PauseScreenEvent(object sender, EventArgs e)
		{
			currentScreen = pauseScreen.BackgroundScreen;
		}
		#endregion

		#region ConfirmQuitDialog.
		private void ConfirmQuitDialogYesEvent(object sender, EventArgs e)
		{
			gui.Screen.Desktop.Children.Remove(confirmQuitDialog);
			if (fadeScreen.BackgroundScreen == mainMenuScreen)
			{
				confirmQuitDialog.IsExitGame = true;
				form.Close();
			}
			else
			{
				fadeScreen.BackgroundScreen.Reset();

				currentScreen.StopMusic();
				currentScreen = mainMenuScreen;
				currentScreen.PlayMusic();
			}
		}

		private void ConfirmQuitDialogNoEvent(object sender, EventArgs e)
		{
			gui.Screen.Desktop.Children.Remove(confirmQuitDialog);
			currentScreen = fadeScreen.BackgroundScreen;
		}
		#endregion

		#region LoadMapDialog.
		private void LoadMapDialogLoadEvent(object sender, EventArgs e)
		{
			gui.Screen.Desktop.Children.Remove(loadMapDialog);
			loadingScreen.Message.Message = "LOADING MAP...";
			loadingScreen.Duration = 5000.0f;
			loadingScreen.Message.TimeToNextLetter = 50.0f;
			loadingScreen.LoadingBar.BorderColor = Color.Black * 0.6f;
			loadingScreen.LoadingBar.BackgroundColor = Color.White * 0.5f;
			loadingScreen.BackgroundImage =
				LoadingScreen.BackgroundImageMode.LoadEditMapScreen;
			loadingScreen.NextScreen = editMapScreen;
			editMapScreen.MapName = loadMapDialog.MapName;
			editMapScreen.LoadMap(editMapScreen.MapName);

			currentScreen.StopMusic();
			currentScreen = loadingScreen;
		}

		private void LoadMapDialogCancelEvent(object sender, EventArgs e)
		{
			gui.Screen.Desktop.Children.Remove(loadMapDialog);
			currentScreen = fadeScreen.BackgroundScreen;
		}
		#endregion

		#region SaveMapDialog.
		private void SaveMapDialogSaveEvent(object sender, EventArgs e)
		{
			gui.Screen.Desktop.Children.Remove(saveMapDialog);

			currentScreen = fadeScreen.BackgroundScreen;

			if (saveMapDialog.Input.Text != null)
			{
				string fileNameWithNoExtension = 
					saveMapDialog.Input.Text.Replace("\r", "").Trim();
				if (fileNameWithNoExtension != string.Empty)
				{
					if (currentScreen is BuildMapScreen)
					{
						((BuildMapScreen)currentScreen).MapName =
							fileNameWithNoExtension + ".bsp";
						((BuildMapScreen)currentScreen).SaveMap(
							((BuildMapScreen)currentScreen).MapName);
						((BuildMapScreen)currentScreen).IsSaved = true;
					}

					saveMapDialog.Input.Text = string.Empty; 
				}
			}
		}

		private void SaveMapDialogCancelEvent(object sender, EventArgs e)
		{
			saveMapDialog.Input.Text = string.Empty;
			gui.Screen.Desktop.Children.Remove(saveMapDialog);
			currentScreen = fadeScreen.BackgroundScreen;
		}
		#endregion

		#region NotifySaveMapDialog.
		private void NotifySaveMapDialogYesEvent(object sender, EventArgs e)
		{
			gui.Screen.Desktop.Children.Remove(notifySaveMapDialog);
			if (fadeScreen.BackgroundScreen is BuildMapScreen)
			{
				if (((BuildMapScreen)fadeScreen.BackgroundScreen).MapName == null)
				{
					saveMapDialog.Title = "Save Map";
					gui.Screen.Desktop.Children.Add(saveMapDialog);
				}
				else
				{
					((BuildMapScreen)fadeScreen.BackgroundScreen).SaveMap(
						((BuildMapScreen)fadeScreen.BackgroundScreen).MapName);
					fadeScreen.BackgroundScreen.Reset();

					currentScreen.StopMusic();
					currentScreen = mainMenuScreen;
					currentScreen.PlayMusic();
				}
			}
		}

		private void NotifySaveMapDialogNoEvent(object sender, EventArgs e)
		{
			gui.Screen.Desktop.Children.Remove(notifySaveMapDialog);
			fadeScreen.BackgroundScreen.Reset();

			currentScreen.StopMusic();
			currentScreen = mainMenuScreen;
			currentScreen.PlayMusic();
		}

		private void NotifySaveMapDialogCancelEvent(object sender, EventArgs e)
		{
			gui.Screen.Desktop.Children.Remove(notifySaveMapDialog);
			currentScreen = fadeScreen.BackgroundScreen;
		}
		#endregion
		#endregion
	}
}
